﻿/*
 
 The contents of this file are subject to the Mozilla Public License Version
 1.1 (the "License"); you may not use this file except in compliance with
 the License. You may obtain a copy of the License at 
 
 http://www.mozilla.org/MPL/ 
 
 Software distributed under the License is distributed on an "AS IS" basis,
 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 for the specific language governing rights and limitations under the License. 
 
 The Original Code is SmileText component.
 
 The Initial Developer of the Original Code is
 Olivier Bugalotto (aka Iteratif) <olivier.bugalotto@iteratif.net>.
 Portions created by the Initial Developer are Copyright (C) 2004-2008
 the Initial Developer. All Rights Reserved.
 
 Contributor(s) :
 
 */
 

package org.iteratif.controls {
	import flash.display.*;
	import flash.net.*;
	import flash.text.engine.*;
	import flash.utils.*;
	
	public class SmileText extends Sprite {
		public var smileCodes:String;
		private var _text:String;
		private var _emoticons:Dictionary;
		private var _font:FontDescription;
		private var __width:Number;
		private var _gap:int = 5;
		
		public function get gap():int {
			return _gap;
		}
		
		public function set gap(value:int):void {
			if(value != gap) {
				_gap = value;
				
				refresh();
			}
		}
		
		public override function get width():Number {
			return __width;
		}
		
		public override function set width(value:Number):void {
			if(value != width) {
				__width = value;
				
				refresh();
			}
		}
		
		public function get font():FontDescription {
			return _font;
		}
		
		public function set font(value:FontDescription):void {
			if(value != _font) {
				_font = value;
				
				refresh();
			}
		}
		
		public function get text():String {
			return _text;
		}
		
		public function set text(value:String):void {
			if(value != text) {
				_text = value;
				
				refresh();
			}
		}
		
		public function SmileText(emoticons:Dictionary = null) {
			_emoticons = emoticons != null ? emoticons : new Dictionary();
			_font = new FontDescription();
			
			createSmileCodes();
		}
		
		protected function render():void {
			if(text) {
				var gp:GroupElement = createGroupElements();
				var tb:TextBlock = new TextBlock();
				tb.content = gp;
				createLines(tb);
			}
		}
		
		protected function clear():void {
			while (numChildren > 0) {
				removeChildAt(0);
			}
		}
		
		private function createLines(textBlock:TextBlock):void {
			var textLine:TextLine = textBlock.createTextLine(null);
			var yPos:Number = textLine.ascent;
			while(textLine) {
				addChild(textLine);
				textLine.y = yPos;
				yPos += textLine.textHeight + gap;
				textLine = textBlock.createTextLine(textLine);
			}
		}
		
		internal function createGroupElements():GroupElement {
			var format:ElementFormat = new ElementFormat(font);
			
			var vectorGp:Vector.<ContentElement> = new Vector.<ContentElement>();
			var splited:Array = splitText();
			for each(var token:String in splited) {
				var smile:DisplayObject;
				var smileCode:* = _emoticons[token];
				if(smileCode) {
					if(smileCode is String) {
						smile = loadEmoticon(smileCode);
					} else if(smileCode is Class) {
						smile = new smileCode();
					}
					// TODO: position smile for baseline text
					vectorGp.push(new GraphicElement(smile,24,smile.height - getTextBaseLine(),format));
				} else {
					vectorGp.push(new TextElement(token,format));
				}
			}
			return new GroupElement(vectorGp);
		}
		
		internal function createSmileCodes():void {
			var codes:Array = [];
			for(var smile:String in _emoticons) {
				codes.push(escapeRegExp(smile));
			}
			smileCodes = codes.join("|");
			smileCodes = "(" + smileCodes + ")";
		}
		
		internal function escapeRegExp(code:String):String {
			return code.replace(/(\(|\)|\.)/gi,"\\$1");
		}
		
		internal function splitText():Array {
			var pattern:RegExp = new RegExp(smileCodes,"gim");
			var splited:Array = text.split(pattern);
			return splited;
		}
		
		internal function getTextBaseLine():Number {
			var format:ElementFormat = new ElementFormat(font);
			
			var ref:TextElement = new TextElement("Wj",format);
			var tb:TextBlock = new TextBlock();
			tb.content = ref;
			var tl:TextLine = tb.createTextLine(null);
			return tl.ascent;
		}
		
		private function refresh():void {
			clear();
			render();
		}
		
		//TODO: using proxy for loading
		private function loadEmoticon(url:String):Loader {
			var loader:Loader = new Loader();
			loader.load(new URLRequest(url));
			return loader;
		}
	}
}